<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      min-height: 500px;
      background: transparent;
      display: flex;
      justify-content: center;
      align-items: center;
      font-family: "SF Mono", SFMono-Regular, Menlo, Monaco, "Cascadia Code", Consolas, "Roboto Mono", "Noto Sans Mono", "Droid Sans Mono", "Ubuntu Mono", "DejaVu Sans Mono", "Liberation Mono", "Courier New", Courier, monospace;
      font-synthesis: none; /* no faux bold/italic width drift */
      font-variant-ligatures: none; /* keep metrics stable for code */
      perspective: 1200px;
      overflow: hidden;
    }

    .scene {
      transform-style: preserve-3d;
      position: relative;
      width: 600px;
      height: 400px;
      transform: translateY(20px) scale(0.8);
    }

    /* Grid Background */
    .grid {
      position: absolute;
      width: 4000px;
      height: 4000px;
      left: -2000px;
      top: -2000px;
      transform: rotateX(34deg) rotateY(7deg) rotateZ(-18deg) translateZ(-300px);
      background-image: 
        linear-gradient(rgba(99, 102, 241, 0.1) 1px, transparent 1px),
        linear-gradient(90deg, rgba(99, 102, 241, 0.1) 1px, transparent 1px);
      background-size: 50px 50px;
    }

    /* Layer Base Styles */
    .layers-container {
      transform-style: preserve-3d;
      width: 100%;
      height: 100%;
      transform: rotateX(25deg) rotateY(43deg) rotateZ(-23deg);
    }

    .layer {
      position: absolute;
      width: 600px;
      height: 276px;
      border-radius: 16px;
      padding: 30px;
      transform-style: preserve-3d;
    }

    /* Top Layer - Textarea */
    .textarea-layer {
      transform: translateZ(150px);
      background: linear-gradient(135deg, rgba(99, 102, 241, 0.05), rgba(139, 92, 246, 0.05));
      border: 2px dashed rgba(99, 102, 241, 0.3);
      backdrop-filter: blur(10px);
      box-shadow: 
        0 20px 40px rgba(99, 102, 241, 0.1),
        inset 0 0 60px rgba(99, 102, 241, 0.05);
    }

    /* Bottom Layer - Preview */
    .preview-layer {
      transform: translateZ(-50px);
      background: linear-gradient(135deg, #ffffff, #f8fafc);
      border: 1px solid rgba(226, 232, 240, 0.8);
      box-shadow: 
        0 25px 50px rgba(0, 0, 0, 0.2),
        0 0 100px rgba(99, 102, 241, 0.1);
    }

    /* Content Styling */
    .markdown-text {
      font-family: "SF Mono", SFMono-Regular, Menlo, Monaco, "Cascadia Code", Consolas, "Roboto Mono", "Noto Sans Mono", "Droid Sans Mono", "Ubuntu Mono", "DejaVu Sans Mono", "Liberation Mono", "Courier New", Courier, monospace;
      font-synthesis: none; /* no faux bold/italic width drift */
      font-variant-ligatures: none; /* keep metrics stable for code */
      font-size: 14px;
      line-height: 18px;
      color: #b1aade;
      text-shadow: 0 0 20px rgba(99, 102, 241, 0.3);
    }

    .markdown-text .code {
      padding: 2px 4px;
      border-radius: 3px;
    }

    .char {
      visibility: hidden;
    }
    
    .char.visible {
      visibility: visible;
    }
    
    .char.current:not(.no-cursor)::after {
      content: '';
      display: inline-block;
      width: 2px;
      height: 18px;
      background: linear-gradient(180deg, #6366f1, #8b5cf6);
      margin-left: 2px;
      box-shadow: 0 0 10px #6366f1;
      animation: blink 1s infinite;
      position: absolute;
    }

    @keyframes blink {
      0%, 50% { opacity: 1; }
      51%, 100% { opacity: 0; }
    }
    
    .char.newline {
      display: block;
      height: 0;
    }

    .list-item {
      color: #64748b;
      margin-left: 20px;
      margin-bottom: 16px;
    }

    .rendered-content h1 {
      color: #d65820;
      font-size: 14px;
      font-weight: 700;
      margin-bottom: 16px;
    }

    .rendered-content p {
      color: #475569;
      font-size: 14px;
      line-height: 20px;
      margin-bottom: 16px;
    }

    .rendered-content strong {
      color: #1e293b;
      font-weight: 600;
    }

    .rendered-content code {
      background: linear-gradient(135deg, #fce7f3, #f9a8d4);
      color: #be185d;
      padding: 3px 8px;
      border-radius: 6px;
      font-family: "SF Mono", SFMono-Regular, Menlo, Monaco, "Cascadia Code", Consolas, "Roboto Mono", "Noto Sans Mono", "Droid Sans Mono", "Ubuntu Mono", "DejaVu Sans Mono", "Liberation Mono", "Courier New", Courier, monospace;
      font-synthesis: none; /* no faux bold/italic width drift */
      font-variant-ligatures: none; /* keep metrics stable for code */
      font-size: 14px;
    }

    .rendered-content li {
      color: #64748b;
      margin-left: 20px;
      margin-bottom: 16px;
    }

    /* Labels */
    .label {
      position: absolute;
      padding: 10px 20px;
      border-radius: 8px;
      font-size: 12px;
      font-weight: 600;
      letter-spacing: 0.5px;
      text-transform: uppercase;
      transform-style: preserve-3d;
    }

    .label-textarea {
      top: -40px;
      left: 30px;
      background: linear-gradient(135deg, rgba(99, 102, 241, 0.9), rgba(139, 92, 246, 0.9));
      color: white;
      transform: translateZ(150px) translateY(-15px);
      box-shadow: 0 10px 30px rgba(99, 102, 241, 0.3);
      padding: 10px 24px 12px;
      font-size: 14px;
    }

    .label-preview {
      bottom: -40px;
      left: 50px;
      background: linear-gradient(135deg, rgba(236, 72, 153, 0.9), rgba(244, 114, 182, 0.9));
      color: white;
      transform: translateZ(-30px) translateY(12px);
      box-shadow: 0 10px 30px rgba(236, 72, 153, 0.3);
      padding: 13px 26px;
      font-size: 15px;
    }

    /* Static Glow Effects */
    .glow {
      position: absolute;
      width: 100%;
      height: 100%;
      border-radius: 16px;
      pointer-events: none;
      opacity: 0.5;
      box-shadow: 
        inset 0 0 50px rgba(99, 102, 241, 0.1),
        0 0 100px rgba(99, 102, 241, 0.05);
    }
  </style>
</head>
<body>
  <div class="scene">
    <!-- Grid Floor -->
    <div class="grid"></div>

    <!-- Layers Container -->
    <div class="layers-container">
      <!-- Top Layer - Invisible Textarea -->
      <div class="layer textarea-layer">
        <div class="label label-textarea">Invisible Textarea</div>
        <div class="markdown-text" id="markdown-text">
          <span id="typed-text"></span>
        </div>
        <div class="glow"></div>
      </div>

      <!-- Bottom Layer - Styled Preview -->
      <div class="layer preview-layer">
        <div class="label label-preview">Rendered Markdown</div>
        <div class="rendered-content" id="rendered-content">
        </div>
      </div>
    </div>
  </div>

  <script>
    // The full text to type
    const fullText = `# Welcome to the editor


This is **bold text** and *italic*


Here's some \`inline code\`


- First item

- Second item

- Third item`;

    // Parse markdown to HTML as we type
    function parseMarkdownLine(line) {
      // Headers
      if (line.startsWith('# ')) {
        return `<h1>${line}</h1>`;
      }
      
      // List items
      if (line.startsWith('- ')) {
        const content = line.substring(2);
        return `<div class="list-item">• ${content}</div>`;
      }
      
      // Regular paragraph with formatting
      let html = line;
      
      // Bold
      html = html.replace(/\*\*([^*]+)\*\*/g, '<strong>**$1**</strong>');
      
      // Italic
      html = html.replace(/\*([^*]+)\*/g, '<em>*$1*</em>');
      
      // Inline code
      html = html.replace(/`([^`]+)`/g, '<code>`$1`</code>');
      
      // Empty line
      if (html.trim() === '') {
        return '<div style="height: 8px;"></div>';
      }
      
      return `<p>${html}</p>`;
    }

    // Convert the typed text to rendered HTML
    function renderMarkdown(text) {
      const lines = text.split('\n');
      const htmlLines = lines.map(line => parseMarkdownLine(line));
      return htmlLines.join('');
    }

    // Pre-process text into character spans
    function createCharacterSpans(text) {
      const container = document.createDocumentFragment();
      let previousWasNewline = false;
      
      for (let i = 0; i < text.length; i++) {
        const char = text[i];
        
        if (char === '\n') {
          if (previousWasNewline) {
            // Add spacer div for the second consecutive newline
            const spacer = document.createElement('div');
            spacer.className = 'char no-cursor';
            spacer.dataset.index = i;
            spacer.innerHTML = '&nbsp;';
            spacer.style.height = '18px';
            container.appendChild(spacer);
            previousWasNewline = false;
          } else {
            // First newline - just add a line break
            const span = document.createElement('span');
            span.className = 'char newline no-cursor';
            span.dataset.index = i;
            span.innerHTML = '<br>';
            container.appendChild(span);
            previousWasNewline = true;
          }
        } else {
          const span = document.createElement('span');
          span.className = 'char';
          span.dataset.index = i;
          span.textContent = char;
          container.appendChild(span);
          previousWasNewline = false;
        }
      }
      
      return container;
    }

    // Animation variables
    const typedElement = document.getElementById('typed-text');
    const renderedElement = document.getElementById('rendered-content');
    let charElements = [];
    let currentIndex = 0;
    let startTime = null;
    const charactersPerSecond = 30; // Typing speed
    const restartDelay = 3000; // Delay before restarting (ms)
    let isWaiting = false;
    let waitStartTime = null;

    // Initialize with all characters hidden
    function initialize() {
      typedElement.innerHTML = '';
      typedElement.appendChild(createCharacterSpans(fullText));
      charElements = typedElement.querySelectorAll('.char');
      renderedElement.innerHTML = '';
    }

    function animate(timestamp) {
      if (!startTime) startTime = timestamp;
      
      if (isWaiting) {
        if (!waitStartTime) waitStartTime = timestamp;
        const waitElapsed = timestamp - waitStartTime;
        
        if (waitElapsed >= restartDelay) {
          // Reset everything
          currentIndex = 0;
          startTime = timestamp;
          isWaiting = false;
          waitStartTime = null;
          
          // Hide all characters
          charElements.forEach(el => {
            el.classList.remove('visible', 'current');
          });
          
          renderedElement.innerHTML = '';
        }
      } else {
        const elapsed = timestamp - startTime;
        const charactersToShow = Math.floor((elapsed / 1000) * charactersPerSecond);
        
        if (charactersToShow > currentIndex && currentIndex < fullText.length) {
          // Show new characters
          for (let i = currentIndex; i < Math.min(charactersToShow, fullText.length); i++) {
            if (i > 0 && charElements[i - 1]) {
              charElements[i - 1].classList.remove('current');
            }
            if (charElements[i]) {
              charElements[i].classList.add('visible');
              charElements[i].classList.add('current');
            }
          }
          
          currentIndex = Math.min(charactersToShow, fullText.length);
          const currentText = fullText.substring(0, currentIndex);
          
          // Update the rendered preview - filter out double newlines for markdown
          const textForMarkdown = currentText.replace(/\n\n+/g, '\n');
          renderedElement.innerHTML = renderMarkdown(textForMarkdown);
        }
        
        // Check if we've finished typing
        if (currentIndex >= fullText.length) {
          isWaiting = true;
        }
      }
      
      requestAnimationFrame(animate);
    }

    // Start the animation
    initialize();
    requestAnimationFrame(animate);
  </script>
</body>
</html>